#pragma once

#include <common_header.h>
#include <utl/deque.h>
#include <utl/memory.h>
#include <condition_variable>

namespace utl
{
	enum class TASK_STATE : u32
	{
		TASK_STATE_NONE,
		//TASK_STATE_BEGIN,
		//TASK_STATE_START,
		//TASK_STATE_RUNING,
		//TASK_STATE_END,
		TASK_STATE_ACTION,
		TASK_STATE_COMPLETED
	};

	struct task_completed_pool;

	class task_base
	{
	public:
		virtual ~task_base();
		virtual void action(bool* par_life) {}//void action(bool* par_life) override
		virtual void completed(){}//void completed() override
		//void on_action();
		//void on_completed();
		//void wait();
		//void run(task_completed_pool* tcp = nullptr);
		//TASK_STATE state{};
	protected:
		//std::mutex locked{};
		//std::condition_variable cv{};
		//bool completed_state{ false };
		//bool action_state{ false };
	private:
#ifdef __GNUC__
		//friend void* child_main(void* par);
#endif // __GNUC__
#ifdef _WINDOWS
		//friend DWORD child_main(LPVOID par);
#endif // _WINDOWS
	};

	struct completed_queue_info
	{
		completed_queue_info(task_base* _task, bool _auto_free) : task{ _task }, auto_free{_auto_free}{}
		task_base* task;
		bool auto_free;
	};

	struct task_completed_pool
	{
		utl::queue<utl::shared_ptr<task_base>> completed_queue{};
		std::mutex locker{};
		void do_thing(u32 task_count = u32_invalid);
		void push(utl::shared_ptr<task_base>);
	};

	union sync_param
	{
		u32 uiv[8];
		void* pv[4];
		u64 ullv[4];
		f32 fv[8];
	};

	using PFN_SYNC_CALLBACK = void(*)(sync_param&);

	struct sync_queue
	{
		struct sync_pair
		{
			sync_pair(PFN_SYNC_CALLBACK c) :callback{ c }
			{}
			sync_pair(PFN_SYNC_CALLBACK c, const sync_param& p) :callback{ c }, param{ p }
			{}
			PFN_SYNC_CALLBACK callback;
			sync_param param;
		};

		utl::queue<sync_pair> container;
		std::mutex locker;

		sync_queue() : container{}, locker{}
		{}

		void push(PFN_SYNC_CALLBACK c)
		{
			std::lock_guard l{ locker };
			container.emplace(c);
		}

		void push(PFN_SYNC_CALLBACK c, const sync_param& p)
		{
			std::lock_guard l{ locker };
			container.emplace(c, p);
		}

		void do_thing(u32 task_count = u32_invalid)
		{
			if (!container.empty())
			{
				std::lock_guard l{ locker };

				for (u32 i{ 0u }; i < task_count && !this->container.empty(); ++i)
				{
					auto& item{ this->container.front() };
					item.callback(item.param);
					this->container.pop();
				}
			}
		}
	};
	
	//void* alloc_task_element(u32 size);
	//void free_task_element(void* _ptr);

	/*struct TASK_DELETER
	{
		void operator()(task_base* ptr)const noexcept
		{
			ptr->~task_base();
			free_task_element(ptr);
		}
	};*/

	//template <typename TASK_TYPE>
	//using task_ptr = eastl::unique_ptr<TASK_TYPE, TASK_DELETER>;

	void async(utl::shared_ptr<task_base>, task_completed_pool* cp);

	template <typename T,typename ... Args>
	void async(task_completed_pool* cp = nullptr, Args&&...args)
	{
		async(make_shared<T>(eastl::forward<Args>(args)...), cp);
	}

	/*template <typename T, typename... Args>
	task_ptr<T> create_task(Args&&...args)
	{
		auto ptr{ alloc_task_element(sizeof(T)) };
		return task_ptr<T>{new(ptr)T(eastl::forward<Args>(args)...)};
	}

	template <typename T, typename... Args>
	task_ptr<T> make_task(Args&&...args)
	{
		auto ptr{ alloc_task_element(sizeof(T)) };
		return new(ptr)T(eastl::forward<Args>(args)...);
	}*/

	bool async_initialize();
	void async_shutdown();
}